<?php

class Bot_Model_Bot
{
    const DB_TABLE='bot';
    const RESOURCE_NAME='bot';
    const USER_AGENT='Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10';
    const METHOD='GET';
    const UPLOAD_DIR='data';
    const IMAGES_FOLDER='uploads';
    const IMAGE_WIDTH=400;
    const IMAGE_HEIGHT=300;
    const AUTHOR_ID = 1;
    const NODE_TYPE = 'node';
    
    protected $_resource;
    protected $_db;
    protected $_db_adapter;
    
    /**
     * Constructor
     * 
     * @param string $resource_name
     */
    public function __construct($resource_name)
    {
        $this->_db=new Bot_Model_BotDb();
        
        $this->_db_adapter=Zend_Registry::get('db');

        try {
            $resource = new Zend_Config_Ini(APPLICATION_PATH.'/modules/bot/resources/'.quotemeta($resource_name).'.ini', 'resource');
        } catch(Exception $e)
        {
            echo $e->getMessage();
            $resource=false;
        }
        
        if (self::isValidResource($resource))
        {
            $this->_resource=$resource;
        }
    }
    
    protected function _initDb()
    {
        $config = new Zend_Config_Ini(APPLICATION_PATH.'/configs/application.ini', 'production');
            
        $this->_db_adapter = Zend_Db::factory($config->resources->db->adapter, array(
                                    'host'     => $config->resources->db->params->host,
                                    'username' => $config->resources->db->params->username,
                                    'password' => $config->resources->db->params->password,
                                    'dbname'   => $config->resources->db->params->dbname
                                ));
                                
        $this->_db_adapter->query('SET NAMES utf8');
    }
    
    /** Fetches data from resource
     * 
     * @return string|bool
     */
    public function fetch()
    {
        if (!self::isValidResource($this->_resource)) return false;
        
        
        $rows=$this->_db->fetchByResource($this->_resource->name);
        
        if (empty($rows))
        {
            $document=$this->_request($this->_resource->collect_uri);
         //   echo $document;
            if (!empty($document))
            {
                $this->_fix_encoding($document);
        
                $this->_collect($document);
            }
            
            return false;
        } else
        {
            $document=$this->_request($this->_resource->uri.'/'.$rows[0]->uri);
        
            $this->_initDb();
        
            $this->_db->save(array(
                                'id' => $rows[0]->id,
                                'parsed' => '1',
                                ),
                                $this->_db_adapter
                            );
            
            $this->_fix_encoding($document);
         //   echo htmlspecialchars($document);            
            return $document;
        }
    }
    
    /**
     * Initializes client and performs request
     * 
     * @param string $uri
     * 
     * @return string|bool
     */
    protected function _request($uri)
    {
        if (!self::isValidResource($this->_resource)) return false;
        
        $client = new Zend_Http_Client();
        $client->setUri($uri);
        $client->setMethod(self::METHOD=='POST' ? Zend_Http_Client::POST : Zend_Http_Client::GET);
        $client->setConfig(array(
                                'adapter'      => 'Zend_Http_Client_Adapter_Socket',
                                'httpversion'  => 1.1,
                                'maxredirects' => 0,
                                'timeout'      => 30,
                                'useragent'    => self::USER_AGENT,
                                'keepalive'    => true
                                )
                            );
        
        if (!empty($this->_resource->params))
        {    
            if (self::METHOD=='POST')              
                $client->setParameterPost($this->_resource->params->toArray());
            else
                $client->setParameterGet($this->_resource->params->toArray());
        }
        
        try {
            $result = $client->request();
            
            return $result->getBody();
            
        } catch(Exception $e)
        {
            return false;
        }
        
    }
    
    /**
     * Checks if given resource is valid
     * 
     * @param object $resource
     * 
     * @return bool
     */
    static function isValidResource($resource)
    {
        if (empty($resource)) return false;
        if (!($resource instanceof Zend_Config_Ini)) return false;
        
        if (!isset($resource->name)) return false;
        if (!isset($resource->encoding)) return false;
        if (!isset($resource->uri)) return false;
        if (!isset($resource->collect_uri)) return false;
        if (!isset($resource->follow)) return false;
        if (!isset($resource->category)) return false;
        if (!isset($resource->pattern->keywords)) return false;
        if (!isset($resource->pattern->title)) return false;
        if (!isset($resource->pattern->teaser)) return false;
        if (!isset($resource->pattern->content)) return false;
        
        return true;
    }
    
    /**
     * Fixes document encoding
     * 
     * @param string $document
     */
    protected function _fix_encoding(&$document)
    {
        if ($this->_resource->encoding != 'utf-8')
        {
            $document=mb_convert_encoding($document,'utf-8',$this->_resource->encoding);
        }
    }
    
    /**
     * Collects URL from given document
     * 
     * @param $document
     */
    protected function _collect(&$document)
    {
        if (preg_match_all('/<a[^>]*href[\x20]*=[\x20]*[\x22\x27]*[\x20]*('.addcslashes($this->_resource->follow,'/?.').'[^\x20\x22\x27\#>]+)[\x20]*[\x22\x27]*[^>]*>/sui',$document,$matches))
        {
            foreach($matches[1] as $match)
            {
              //  $uri=trim(str_replace($this->_resource->uri,'',$match),'/');
                
                $uri=str_replace($this->_resource->uri,'',$match);
                
                if (substr($uri,0,1)=='/')
                {
                    $uri=substr($uri,1);
                }
                
                $ex=$this->_db->fetchByUriAndResource($uri,$this->_resource->name);
                if (!empty($ex)) continue;
                
                $row=array(
                        'resource' => $this->_resource->name,
                        'uri' => $uri,
                        'parsed' => '0',
                        'tstamp' => time()
                        );
                        
                $this->_db->save($row);
            }
        }
    }
    
    /**
     * Alternates content
     * 
     * @param string $document
     */
    public function alterContent(&$document)
    {
        $document=str_replace('—','-',$document);
        $document=str_replace('ё','е',$document);
    }
    
    /**
     * Parse document keywords
     * 
     * @param string $document
     * 
     * @return string
     */
    public function getKeywords($document)
    {
        $content=$this->_getElementContent($document,$this->_resource->pattern->keywords);

        return $content;
    }
    
    /**
     * Parse document title
     * 
     * @param string $document
     * 
     * @return string
     */
    public function getTitle($document)
    {
        $content=$this->_getElementContent($document,$this->_resource->pattern->title);

        return html_entity_decode($content);
    }
    
    /**
     * Parse document teaser
     * 
     * @param string $document
     * 
     * @return string
     */
    public function getTeaser($document)
    {
        $content=$this->_getElementContent($document,$this->_resource->pattern->teaser);

        if (isset($this->_resource->teaser_max_length) && mb_strlen($content,'utf-8')>$this->_resource->teaser_max_length)
        {
            $p=mb_strpos($content,'.',$this->_resource->teaser_max_length,'utf-8');
            $content=mb_substr($content,0,$p+1,'utf-8');
        }

        return $content;
    }
    
    /**
     * Parse document content
     * 
     * @param string $document
     * 
     * @return string
     */
    public function getContent($document)
    {
        $content=$this->_getElementContent($document,$this->_resource->pattern->content);

        return $content;
    }
    
    /**
     * Searches for pattern in given document
     * 
     * @param string $document
     * @param string $pattern
     * 
     * @return string
     */
    protected function _getElementContent(&$document,$pattern)
    {

        if (!preg_match('/'.addcslashes($pattern,'/').'/sui',$document,$matches)) return ;
        
        return isset($matches[1]) ? $matches[1] : $matches[0];
    }
    
    /**
     * Downloads images and replaces them in given document
     * 
     * @param string $document
     */
    public function replaceImages(&$document)
    {
        if (preg_match_all('/<img[^>]*src[\x20]*=[\x20]*[\x22\x27]*[\x20]*([^\x22\x27>]+)[\x20]*[\x22\x27]*[^>]*>/sui',
                            $document,
                            $matches))
        {
            foreach($matches[1] as $id=>$match)
            {
                $uri=trim(str_replace($this->_resource->uri,'',$match),'/');
                
                $img=file_get_contents($this->_resource->uri.'/'.html_entity_decode($uri));
                
                if (!empty($img))
                { 
                    $file_ext='thumb';
                    
                    do {
                        $filename=md5($match.microtime(true));
                    } while(file_exists(ROOT_DIR.'/'.self::UPLOAD_DIR.'/'.self::IMAGES_FOLDER.'/'.$filename.'.'.$file_ext));
                    
                    $file=fopen(ROOT_DIR.'/'.self::UPLOAD_DIR.'/'.self::IMAGES_FOLDER.'/'.$filename.'.'.$file_ext,'wb');
                    if (!$file) break;
                    
                    fwrite($file,$img);
                    fclose($file);
                    
                    $newImage='<img src="'.trim(Zend_Registry::get('view')->fixUrl(),'/').'/'.self::UPLOAD_DIR.'/'.self::IMAGES_FOLDER.'/'.$filename.'.'.$file_ext.'" />';
                    
                    require_once(APPLICATION_PATH.'/views/helpers/Image.php');
                    
                    $img=new Helper_Image();
                    $img->setView(Zend_Registry::get('view'));
                    
                    $newImage=$img->image(self::IMAGES_FOLDER,$filename,$file_ext,self::IMAGE_WIDTH,self::IMAGE_HEIGHT);
                    
                } else
                {
                    $newImage='';
                }
                
                $document=str_replace($matches[0][$id],
                                    '<div style="text-align: center;margin:20px">'.$newImage.'</div>',
                                    $document);
            }
        }
    }
    
    /**
     * Strips tags in given document
     * 
     * @param string $document
     * @param string $tags (all|format|content)
     */
    public function stripTags(&$document,$tags='all')
    {
        if ($tags=='all') $document=strip_tags($document);
        if ($tags=='format') $document=strip_tags($document,'<br /><BR /><br><BR>');
        if ($tags=='content') $document=strip_tags($document,'<br /><BR /><br><BR><p><P><img><IMG><b><B><strong><STRONG><em><EM><i><I><u><U><s><S><strike><STRIKE><center><CENTER>');
    }
    
    /**
     * Performs defined replacements in document
     * 
     * @param string $document
     */
    public function doReplace(&$document)
    {
        if (isset($this->_resource->strip))
        {
            $strip=$this->_resource->strip->toArray();
            $replace=array();
            if (isset($this->_resource->replace))
            {
                $replace=$this->_resource->replace->toArray();
            }
            
            foreach($strip as $id=>$pattern)
            {
                $document=preg_replace('/'.addcslashes($pattern,'/').'/sui',
                                    array_key_exists($id,$replace) ? $replace[$id] : '',
                                    $document);                  
            }
        }
    }
    
    /**
     * Adds link to resource
     * 
     * @param string $document
     */
    public function addLink(&$document)
    {
        if (!isset($this->_resource->add_link) || !$this->_resource->add_link) return;
        
        $document=$document.'<p style="text-align:right"><noindex>'.Zend_Registry::get('locale')->_('Source').': <a href="'.$this->_resource->uri.'" rel="nofollow" target="_blank">'.str_replace('http://','',$this->_resource->uri).'</a></noindex></p>';
    }
    
    /**
     * Generates node URL alias from its title
     * 
     * @param string $title
     * 
     * @return string
     */
    static function title2url($title)
    {
        $url=mb_strtolower(trim($title),'utf-8');
        
        $url=str_replace(' ','-',$url);
        
        $url=preg_replace('/[^a-zа-я0-9]/u','-',$url);
        $url=preg_replace('/[-]{2,}/u','-',$url);
        $url=trim($url,'-');
        
        return $url;
    }
    
    /**
     * Saves node to database
     * 
     * @param string $keywords
     * @param string $title
     * @param string $teaser
     * @param string $content
     */
    public function saveNode(&$keywords,&$title,&$teaser,&$content)
    {
        $node=array(
            'title' => $title,
            'short_text' => $teaser,
            'full_text' => $content,
            'publish_date' => date('Y-m-d'),
            'published' => isset($this->_resource->publish) && $this->_resource->publish ? 1 : 0,
            'front' => isset($this->_resource->front) && $this->_resource->front ? 1 : 0,
            'uid' => self::AUTHOR_ID,
            'type' => self::NODE_TYPE,
            'category' => $this->_resource->category,
            'url_alias' => self::title2url($title),
            'language' => Zend_Registry::get('language')->getLocale(),
            'meta' => array(
                        'keywords' => $keywords,
                        'description' => $teaser,
                        'thumbnail_filename' => '',
                        'thumbnail_ext' => ''
                      )
        );
        
        //creating thumbnail
        if (!empty($content) && preg_match('/<img[^>]+src[\x20]*[=][\x20]*[\x22]('.addcslashes(Zend_Registry::get('view')->siteUrl(),'/').')?(.+?)[\x22][^>]*>/si',$content,$matches))
        {
            $img_url=trim($matches[2],'/');
            
            if (file_exists(ROOT_DIR.'/'.$img_url))
            {
                if (preg_match('/^data\/uploads\/([^\.]+?)\.(.+?)$/',$img_url,$img_match) || 
                    preg_match('/^data\/thumbs\/uploads\/([^\.]+?)\.(.+?)_'.self::IMAGE_WIDTH.'x'.self::IMAGE_HEIGHT.'$/',$img_url,$img_match))
                {
                    $node['meta']['thumbnail_filename']=$img_match[1];
                    $node['meta']['thumbnail_ext']=$img_match[2];
                }
            }
        }

        // parse text for tags
        $parser=new Parser_Model_Parser();
        
        if (isset($this->_resource->keywords_delimiter))
        {
            if (!empty($keywords))
            {
                $tags=explode($this->_resource->keywords_delimiter,$keywords);
                
                foreach($tags as $tag)
                {
                    $this->_prepareTag($tag);
                    
                    if (mb_strlen($tag,'utf-8')<3) continue;
        
                    $parser->parse($tag,$node['full_text']);
                }
            }
        }
        
        $this->_initDb();
        
        $nodeObj=new Application_Model_Node($node);
        
        $nodeTbl=new Application_Model_NodeDb();
        
        $ex=$nodeTbl->fetchNodesByClause(array(
            'type' => self::NODE_TYPE,
            'title' => $node['title']
            )
        );
        
        if (!empty($ex)) return;
        
        $nid=$nodeTbl->save($nodeObj,$this->_db_adapter);
        
        // creating tags
        if (!empty($nid) && isset($this->_resource->keywords_delimiter))
        {
            $tagsTbl=new Application_Model_TagsDb();
        
            if (!empty($tags))
            {
                foreach($tags as $tag)
                {
                    $this->_prepareTag($tag);
                    
                    if (mb_strlen($tag,'utf-8')<3) continue;
                    
                    $tagObj=new Application_Model_Tags(array(
                                                        'tag' => trim($tag),
                                                        'nid' => $nid,
                                                        'url_alias' => $node['url_alias'],
                                                        'language' => $node['language']
                                                        ));
                    
                    $tagsTbl->save($tagObj,$this->_db_adapter);
                }
            }
        }

        //clearing cache
        $cache=Zend_Registry::get('cache');
        $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
        
    }
    
    /**
     * Prepares tag for saving to database
     * 
     * @param string $tag
     */
    protected function _prepareTag(&$tag)
    {
        $tag=mb_strtolower($tag,'utf-8');
        
        $tag=preg_replace('/[^a-zа-яё0-9_\x20-]/ui','',$tag);
        
        $tag=trim($tag);
    }
}

